package transport

import (
	"bytes"
	"encoding/binary"
	"lnzw/engine/actor"
	"lnzw/engine/log"
	"lnzw/server/test/test_fyne/test_3/pbmsg"
	"lnzw/server/test/test_fyne/test_3/router"

	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
)

type ProtoDefaultHandler struct {
	rspMsg actor.Msg
}

func (p *ProtoDefaultHandler) retRsp() {
	p.rspMsg.Data = nil
	p.rspMsg.SourceId = ""
	p.rspMsg.SyncRsp = nil
}

func (p *ProtoDefaultHandler) Handle(msg actor.Msg) {
	defer func() {
		if r := recover(); r != nil {
			log.Error("panic", zap.Error(r.(error)))
		}
	}()
	l := len(msg.Data)
	if l < 4 {
		log.Error("data error")
		return
	}
	h := binary.BigEndian.Uint32(msg.Data[0:4])
	handler := router.GetHandler(h)
	if handler == nil {
		log.Error("handler not found")
		return
	}
	pbreq, pbrsp := pbmsg.GetMsg(h)
	if pbreq == nil || pbrsp == nil {
		log.Error("request or response not found")
		return
	}
	err := proto.Unmarshal(msg.Data[4:], pbreq)
	if err != nil {
		log.Error("unmarshal failed", zap.Any("err", err))
	}
	handler(pbreq, pbrsp)
	if pbrsp != pbmsg.GetDefaultResNot() {
		p.sendRsp(msg, h, pbrsp)
	}
}

func (p *ProtoDefaultHandler) sendRsp(msg actor.Msg, hash uint32, pbrsp proto.Message) {
	rspfunc := func() {
		defer func() {
			if r := recover(); r != nil {
				log.Error("actor.retRsp panic", zap.Any("err", r))
			}
		}()
		if msg.SyncRsp != nil {
			//判断channel是否关闭
			select {
			case msg.SyncRsp <- p.rspMsg:
			default:
				log.Warn("actor.retRsp reply timeout")
			}
		} else {
			if msg.SourceId != "" {
				actor.Send("", msg.SourceId, p.rspMsg.Data)
			}
		}
	}
	buildRsp := func(pb proto.Message) {
		var buff bytes.Buffer
		binary.Write(&buff, binary.BigEndian, hash)
		bs, err := proto.Marshal(pb)
		if err != nil {
			log.Error("send error", zap.Any("err", err))
			return
		}
		buff.Write(bs)
		p.rspMsg.Data = buff.Bytes()
	}
	buildRsp(pbrsp)
	rspfunc()
	p.retRsp()
}
